home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Online / Qpopper / pop_dropcopy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-19  |  26.8 KB  |  994 lines

  1. /*
  2.  * Copyright (c) 1989 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7.  
  8. /*
  9.  * When adding each line length into the size of the message and the maildrop,
  10.  * increase the character count by one for the <cr> added when sending the
  11.  * message to the mail client.  All lines sent to the client are terminated
  12.  * with a <cr><lf>.
  13.  */
  14.  
  15.  
  16. #ifndef lint
  17. static char copyright[] = "Copyright (c) 1990 Regents of the University of California.\nAll rights reserved.\n";
  18. static char SccsId[] = "@(#)@(#)pop_dropcopy.c    2.6  2.6 4/3/91";
  19. #endif
  20.  
  21.  
  22. #include <errno.h>
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <ctype.h>
  26. #ifdef SYSV
  27. # include    <string.h>
  28. # include     <unistd.h>    /* Maybe /sys/unistd.h on HPUX */
  29. # include    "flock.h"
  30. # ifndef index
  31. #  define    index(s,c)        strchr(s,c)
  32. # endif
  33. # ifndef rindex
  34. #  define    rindex(s,c)        strrchr(s,c)
  35. # endif
  36. #else
  37. # include <strings.h>
  38. #endif
  39. #include <sys/stat.h>
  40. #include <sys/file.h>
  41. #include <pwd.h>
  42. #include "popper.h"
  43.  
  44.  
  45. #if defined(HAVE_UNISTD_H) || defined(SUNOS4)
  46. #include <unistd.h>
  47. #endif
  48.  
  49. #ifdef MAILOCK
  50. # include <maillock.h>
  51. #endif
  52.  
  53. #if defined(SYSV) && !defined(L_XTND)
  54. # define L_XTND SEEK_END
  55. #endif
  56.  
  57. #include "md5.h"
  58.  
  59. /* This macro comes from Mark Crispin's c-client code */
  60.  
  61. /* Validate line
  62.  * Accepts: pointer to candidate string to validate as a From header
  63.  *        return pointer to end of date/time field
  64.  *        return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  65.  *        return pointer to offset from t of time zone (if non-zero)
  66.  * Returns: t,ti,zn set if valid From string, else ti is NIL
  67.  */
  68.  
  69. #define VALID(s,x,ti,zn) {                        \
  70.   ti = 0;                                \
  71.   if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&    \
  72.       (s[4] == ' ')) {                            \
  73.     for (x = s + 5; *x && *x != '\n'; x++);                \
  74.     if (x) {                                \
  75.       if (x - s >= 41) {                        \
  76.     for (zn = -1; x[zn] != ' '; zn--);                \
  77.     if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&    \
  78.         (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&    \
  79.         (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&    \
  80.         (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
  81.       x += zn - 12;                            \
  82.       }                                    \
  83.       if (x - s >= 27) {                        \
  84.     if (x[-5] == ' ') {                        \
  85.       if (x[-8] == ':') zn = 0,ti = -5;                \
  86.       else if (x[-9] == ' ') ti = zn = -9;                \
  87.       else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))    \
  88.         ti = zn = -11;                        \
  89.     }                                \
  90.     else if (x[-4] == ' ') {                    \
  91.       if (x[-9] == ' ') zn = -4,ti = -9;                \
  92.     }                                \
  93.     else if (x[-6] == ' ') {                    \
  94.       if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))    \
  95.         zn = -6,ti = -11;                        \
  96.     }                                \
  97.     if (ti && !((x[ti - 3] == ':') &&                \
  98.             (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&    \
  99.             (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&        \
  100.             (x[ti - 11] == ' '))) ti = 0;            \
  101.       }                                    \
  102.     }                                    \
  103.   }                                    \
  104. }
  105.  
  106. /* You are not expected to understand this macro, but read the next page if
  107.  * you are not faint of heart.
  108.  *
  109.  * Known formats to the VALID macro are:
  110.  *         From user Wed Dec  2 05:53 1992
  111.  * BSD        From user Wed Dec  2 05:53:22 1992
  112.  * SysV        From user Wed Dec  2 05:53 PST 1992
  113.  * rn        From user Wed Dec  2 05:53:22 PST 1992
  114.  *        From user Wed Dec  2 05:53 -0700 1992
  115.  *        From user Wed Dec  2 05:53:22 -0700 1992
  116.  *        From user Wed Dec  2 05:53 1992 PST
  117.  *        From user Wed Dec  2 05:53:22 1992 PST
  118.  *        From user Wed Dec  2 05:53 1992 -0700
  119.  * Solaris    From user Wed Dec  2 05:53:22 1992 -0700
  120.  *
  121.  * Plus all of the above with `` remote from xxx'' after it. Thank you very
  122.  * much, smail and Solaris, for making my life considerably more complicated.
  123.  */
  124.  
  125.  
  126. int newline = 1;
  127.  
  128. /*
  129.  *  0 for not a from line
  130.  *  1 for is a from line
  131.  */
  132.  
  133. /* Valid UUCP From lines:
  134.  *
  135.  *    From Address [tty] date
  136.  *    From [tty] date
  137.  *
  138.  *    "From [tty] date" is probably valid but I'm to lazy at this
  139.  *    time to add the code.
  140.  *
  141.  */
  142. int
  143. isfromline(cp)
  144. char    *cp;
  145. {
  146.     int ti, zn;
  147.     char *x;
  148.  
  149.     /* If the previous line was not a newline then just return */
  150.     /* From message separators are preceeded by a newline */ 
  151.     if (*cp == '\n') {
  152.     newline = 1;
  153.     return(0);
  154.     } else if (!newline) {
  155.     return(0);
  156.     } else
  157.     newline = 0;
  158.  
  159. #ifndef NOVALIDATE
  160.     VALID(cp, x, ti, zn);
  161.     return(ti != 0);
  162. #else
  163.     return(strncmp(cp,"From ",5)==0);
  164. #endif
  165. }
  166.  
  167. /* Hashing to a spool directory helps reduce the lookup time for sites
  168.  * with thousands of mail spool files.  Unix uses a linear list to
  169.  * save directory information and the following methods attempt to
  170.  * improve the performance.
  171.  *
  172.  * Method 1 - add the value of the first 4 chars mod 26 and open the
  173.  *          spool file in the directory 'a' - 'z'/user.
  174.  *          Brian Buhrow <buhrow@cats.ucsc.edu>
  175.  *
  176.  * Method 2 - Use the first 2 characters to determine which mail spool
  177.  *          to open.  Eg: /usr/spool/u/s/user.
  178.  *          Larry Schwimmer <rosebud@cyclone.stanford.edu>
  179.  *
  180.  * All these methods require that local mail delivery and client programs
  181.  * use the same algorithm.  Only one method to a customer :-)
  182.  */
  183.  
  184. #if (HASH_SPOOL == 1)
  185.  
  186. int
  187. genpath(p)
  188. POP *p;
  189. {
  190.     int seed = 0;
  191.     char dirchar[4];
  192.  
  193.     if (!p->user || *p->user == '\0')
  194.     return(NULL); /*bogus login name*/
  195.  
  196.     /*Now, perform the hash*/
  197.  
  198.     switch(strlen(p->user)) {
  199.        case 1:
  200.        seed = (p->user[0]);
  201.        break;
  202.        case 2:
  203.        seed = (p->user[0] + p->user[1]);
  204.        break;
  205.        case 3:
  206.        seed = (p->user[0] + p->user[1] + p->user[2]);
  207.        break;
  208.        case 4:
  209.        seed = (p->user[0] + p->user[1] + p->user[2]+p->user[3]);
  210.        break;
  211.        default:
  212.        seed = (p->user[0] + p->user[1] + p->user[2]+p->user[3]+p->user[4]);
  213.        break;
  214.     }
  215.     dirchar[0] = '/';
  216.     dirchar[1] = (char)((seed % 26) + 'a');
  217.     dirchar[2] = '/';
  218.     dirchar[3] = '\0';
  219.     strncpy(p->drop_name, POP_MAILDIR, sizeof(p->drop_name));
  220.     strncat(p->drop_name, dirchar, sizeof(p->drop_name) - strlen(p->drop_name));
  221.     strncat(p->drop_name, p->user, sizeof(p->drop_name) - strlen(p->drop_name));
  222.  
  223.     return(1);
  224. }
  225.  
  226. #endif
  227. #if (HASH_SPOOL == 2)
  228.  
  229. int
  230. genpath(p)
  231. POP *p;
  232. {
  233.     static char pathstr[256];
  234.  
  235.     if (!p->user || *p->user == '\0')
  236.     return(NULL);
  237.     
  238.     sprintf(pathstr, "/%c/%c/%s",
  239.             *p->user, *(p->user+1) ? *(p->user+1) : *p->user, p->user);
  240.  
  241.     strncpy(p->drop_name, POP_MAILDIR, sizeof(p->drop_name));
  242.     strncat(p->drop_name, pathstr, sizeof(p->drop_name) - strlen(p->drop_name));
  243.  
  244.     return(1);
  245. }
  246.  
  247. #endif
  248. #if (HASH_SPOOL != 1 && HASH_SPOOL != 2)
  249.  
  250. int
  251. genpath(p)
  252. POP *p;
  253. {
  254.     struct passwd *pwp;
  255.  
  256. #ifdef HOMEDIRMAIL
  257.     if ((pwp = getpwnam(p->user)) == NULL) {
  258.     pop_log(p, POP_FAILURE, "unable to retrieve users password entry");
  259.     return(-1);
  260.     }
  261.     strncpy(p->drop_name, pwp->pw_dir, sizeof(p->drop_name));
  262.     strncat(p->drop_name, "/.mail",sizeof(p->drop_name) - strlen(p->drop_name));
  263. #else
  264.     strncpy(p->drop_name, POP_MAILDIR, sizeof(p->drop_name));
  265.     strncat(p->drop_name, "/", sizeof(p->drop_name) - strlen(p->drop_name));
  266.     strncat(p->drop_name, p->user, sizeof(p->drop_name) - strlen(p->drop_name));
  267. #endif
  268.  
  269.     return(1);
  270. }
  271.  
  272. #endif /* HASH_SPOOL */
  273.  
  274.  
  275. /* Open and check the .user.pop file and gather info before copying over
  276.  * the users mailbox.
  277.  */
  278. int init_dropinfo(p)
  279. POP *p;
  280. {
  281.     MsgInfoList         *   mp;         /* Pointer to message info list */
  282.     int                msg_num;    /* Current message number */
  283.     int                nchar;
  284.     int                inheader;
  285.     int                uidl_found;
  286.     int                expecting_trailer;
  287.     int                content_length, content_nchar, cont_len;
  288.     char                    buffer[MAXLINELEN];        /*  Read buffer */
  289.     MD5_CTX            mdContext;
  290.     unsigned char        digest[16];
  291.  
  292. #ifdef DEBUG
  293.     if(p->debug)
  294.     pop_log(p,POP_DEBUG, "Checking for old .%s.pop file", p->user);
  295. #endif
  296.  
  297.     /*  Allocate memory for message information structures */
  298.     p->mlp = (MsgInfoList *)calloc((unsigned)ALLOC_MSGS,sizeof(MsgInfoList));
  299.     if (p->mlp == NULL){
  300.         return pop_msg (p,POP_FAILURE,
  301.             "Can't build message list for '%s': Out of memory", p->user);
  302.     }
  303.  
  304.     p->msg_count = 0;
  305.     p->drop_size = 0;
  306.  
  307. #ifdef NULLKLUDGE
  308.   /* Kludge to get around NULLs at the beginning of the mailspool */
  309.   while ((tempchar = getc(p->drop)) == 0);
  310.   ungetc(tempchar, p->drop);
  311. #endif
  312.  
  313.     if (fgets(buffer, MAXMSGLINELEN, p->drop) == NULL) {
  314. #ifdef DEBUG
  315.     if(p->debug)
  316.         pop_log(p,POP_DEBUG, "Old .%s.pop file not found, errno (%d)",
  317.                                 p->user, errno);
  318. #endif
  319.  
  320.     return(POP_SUCCESS);
  321.     }
  322.  
  323.     /* Is this an MMDF file? */
  324.     if (*buffer == MMDF_SEP_CHAR) {
  325.     p->mmdf_separator = (char *)strdup(buffer);
  326.     } else if (!isfromline(buffer)) {
  327.     return pop_msg (p,POP_FAILURE,
  328.       "Unable to process From lines (envelopes), change recognition modes.");
  329.     }
  330.  
  331.     newline = 1;
  332.     rewind(p->drop);
  333.  
  334.     inheader = 0;
  335.     msg_num = 0;
  336.     uidl_found = 0;
  337.     expecting_trailer = 0;
  338.     content_length = 0;
  339.     content_nchar = 0;
  340.     cont_len = 0;
  341.     p->msg_count = ALLOC_MSGS;
  342.  
  343. #ifdef NULLKLUDGE
  344.   /* Kludge to get around NULLs at the beginning of the mailspool */
  345.   while ((tempchar = getc(p->drop)) == 0);
  346.   ungetc(tempchar, p->drop);
  347. #endif
  348.  
  349.     for (mp=p->mlp - 1; fgets(buffer, MAXMSGLINELEN, p->drop);) {
  350.     nchar = strlen(buffer);
  351.  
  352.     if ((content_nchar >= content_length) &&
  353.         (p->mmdf_separator ? !strcmp(p->mmdf_separator, buffer) :
  354.         isfromline(buffer))) {
  355.  
  356.         if (expecting_trailer) {
  357.         /* skip over the MMDF trailer */
  358.         expecting_trailer = 0;
  359.         continue;
  360.         }
  361.  
  362.         MD5Init (&mdContext);
  363.         MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  364.  
  365.         if (!inheader) {
  366.         if (++msg_num > p->msg_count) {
  367.             p->mlp = (MsgInfoList *) realloc(p->mlp,
  368.             (p->msg_count += ALLOC_MSGS) * sizeof(MsgInfoList));
  369.             if (p->mlp == NULL){
  370.             p->msg_count = 0;
  371.             return pop_msg (p, POP_FAILURE,
  372.                 "Can't build message list for '%s': Out of memory",
  373.                     p->user);
  374.             }
  375.             mp = p->mlp + msg_num - 2;
  376.         }
  377. #ifdef DEBUG
  378.         if(p->debug && msg_num != 1)
  379.             pop_log(p, POP_DEBUG,
  380.         "Msg %d uidl %s at offset %d is %d octets long and has %u lines.",
  381.         mp->number, mp->uidl_str, mp->offset, mp->length, mp->lines);
  382.         else
  383.             pop_log(p,POP_DEBUG, "Found top of first message");
  384. #endif
  385.         ++mp;
  386.  
  387.         } else {
  388.         pop_log(p,POP_DEBUG,
  389.             "Msg %d corrupted, ignoring previous header information.",
  390.              mp->number);
  391.         }
  392.         mp->number = msg_num;
  393.         mp->length = 0;
  394.         mp->lines = 0;
  395.         mp->body_lines = 0;
  396.         mp->offset = ftell(p->drop) - nchar;
  397.         mp->del_flag = FALSE;
  398.         mp->retr_flag = FALSE;
  399.         mp->orig_retr_state = FALSE;
  400.         mp->uidl_str = "\n";
  401. #ifdef DEBUG
  402.         if(p->debug)
  403.         pop_log(p,POP_DEBUG, "Msg %d being added to list", mp->number);
  404. #endif
  405.         inheader = 1;
  406.         uidl_found = 0;
  407.         content_nchar = 0;
  408.         content_length = 0;
  409.         cont_len = 0;
  410.         if (p->mmdf_separator)
  411.         expecting_trailer = 1;
  412.         
  413.         continue;    /* Don't count message separator in total size */
  414.     }
  415.     
  416.     if (inheader) {
  417.         if (*buffer == '\n') {
  418.         inheader = 0;
  419.         content_length = cont_len;
  420.         mp->body_lines = 1;  /* Count newline as the first body line */
  421.         if (!uidl_found) {
  422.             char    *cp;
  423.             int        i;
  424.  
  425.             MD5Final (digest, &mdContext);
  426.             cp = mp->uidl_str = (char *)malloc((DIG_SIZE * 2) + 2);
  427.  
  428.             for (i = 0; i < DIG_SIZE; i++, cp+=2) {
  429.             sprintf(cp, "%02x", digest[i]);
  430.             }
  431.             *cp++ = '\n';
  432.             *cp   = '\0';
  433.  
  434.             mp->length += strlen("X-UIDL: ") + strlen(mp->uidl_str) + 1;
  435.             p->drop_size += strlen("X-UIDL: ") + strlen(mp->uidl_str)+1;
  436.  
  437.     /* New UIDs do not dirty the mailspool if NO_STATUS is set.  They
  438.        are just recalculated each time the popper is run or LMOS is
  439.        set and the mail spool is updated.
  440.      */
  441. #ifndef NO_STATUS
  442.             p->dirty = 1;
  443. #endif
  444.         }
  445.  
  446.         } else if (CONTENT_LENGTH && !strncmp(buffer, "Content-Length:", 15)) {
  447.         cont_len = atoi(buffer + 15);
  448.         MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  449.         continue;    /* not part of the message size */
  450.         } else if (!uidl_found && (!strncasecmp("Received:", buffer, 9) ||
  451.                        !strncasecmp("Date:", buffer, 5) ||
  452.                        !strncasecmp("Message-Id:",buffer, 11) ||
  453.                        !strncasecmp("Subject:",buffer, 8)
  454.                        )) {
  455.         MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  456.         } else if (!strncasecmp("X-UIDL:", buffer, 7)) {
  457.         if (!uidl_found) {
  458.             char *cp;
  459.  
  460.             uidl_found++;
  461.             /* Skip over header string */
  462.             cp = buffer;
  463.             if (cp = index(buffer, ':')) {
  464.             cp++;
  465.             while (*cp && (*cp == ' ' || *cp == '\t')) cp++;
  466.             } else
  467.             cp = "";
  468.  
  469.             mp->uidl_str = (char *)strdup(cp);
  470.             mp->length += nchar + 1;
  471.             p->drop_size += nchar + 1;
  472.         }
  473.         continue;  /* Do not include this value in the message size */
  474.         } else if ((strncasecmp(buffer,"Status:",7) == 0)) {
  475.         if (index(buffer, 'R') != NULL) {
  476.             mp->retr_flag = TRUE;
  477.             mp->orig_retr_state = TRUE;
  478.         }
  479.         }
  480.     } else {
  481.         content_nchar += nchar;
  482.         mp->body_lines++;
  483.     }
  484.  
  485.     mp->length += nchar + 1;
  486.     p->drop_size += nchar + 1;
  487.     mp->lines++;
  488.     }
  489.  
  490.     p->msg_count = msg_num;
  491.  
  492.     return(POP_SUCCESS);
  493. }
  494.  
  495.  
  496. /* 
  497.  *  use to be dropinfo:   Extract information about the POP maildrop and store 
  498.  *  it for use by the other POP routines.
  499.  *
  500.  *  Now, the copy and info collection are done at the same time.
  501.  */
  502.  
  503. do_drop_copy(p, mfd, dfd)
  504. int    mfd, dfd;
  505. POP    *p;
  506. {
  507.     char                    buffer[MAXLINELEN];     /*  Read buffer */
  508.     MsgInfoList         *   mp;                     /*  Pointer to message 
  509.                                                         info list */
  510.     int                     nchar;                  /*  Bytes written/read */
  511.     int                inheader;            /*  Header section flag */
  512.     int                uidl_found;            /*  UIDL header flag */
  513.     int                msg_num;
  514.     int                expecting_trailer;
  515.     int                content_length, content_nchar, cont_len;
  516.     MD5_CTX            mdContext;
  517.     unsigned char        digest[16];
  518.  
  519.     FILE            *mail_drop;            /*  Streams for fids */
  520.  
  521.     /*  Acquire a stream pointer for the maildrop */
  522.     if ( (mail_drop = fdopen(mfd,"r")) == NULL ) {
  523.         (void)close(mfd) ;
  524.         return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s (%d)",
  525.             p->drop_name, errno);
  526.     }
  527.  
  528.     rewind (mail_drop);
  529.  
  530. #ifdef NULLKLUDGE
  531.   /* Kludge to get around NULLs at the beginning of the mailspool */
  532.   while ((tempchar = getc(p->drop)) == 0);
  533.   ungetc(tempchar, p->drop);
  534. #endif
  535.  
  536.     if (fgets(buffer, MAXMSGLINELEN, mail_drop) == NULL) {
  537.     return(POP_SUCCESS);
  538.     }
  539.  
  540.     /* Is this an MMDF file? */
  541.     if (*buffer == MMDF_SEP_CHAR) {
  542.     if (!p->mmdf_separator)
  543.         p->mmdf_separator = (char *)strdup(buffer);
  544.     } else if (!isfromline(buffer)) {
  545.     return pop_msg (p,POP_FAILURE,
  546.      "Unable to process From lines (envelopes), change recognition modes.");
  547.     }
  548.  
  549.     newline = 1;
  550.     rewind (mail_drop);
  551.  
  552.     /*  Scan the file, loading the message information list with 
  553.         information about each message */
  554.  
  555.     inheader = 0;
  556.     uidl_found = 0;
  557.     expecting_trailer = 0;
  558.     msg_num = p->msg_count;
  559.     content_length = 0;
  560.     content_nchar = 0;
  561.     cont_len = 0;
  562.     p->msg_count = (((p->msg_count - 1) / ALLOC_MSGS) + 1) * ALLOC_MSGS;
  563.  
  564. #ifdef NULLKLUDGE
  565.   /* Kludge to get around NULLs at the beginning of the mailspool */
  566.   while ((tempchar = getc(p->drop)) == 0);
  567.   ungetc(tempchar, p->drop);
  568. #endif
  569.  
  570.     for (mp = p->mlp + msg_num - 1; fgets(buffer,MAXMSGLINELEN,mail_drop);) {
  571.  
  572.     nchar = strlen(buffer);
  573.  
  574.     if (fputs(buffer, p->drop) == EOF) {
  575. #ifdef EDQUOT
  576.         if (errno == EDQUOT)
  577.         return pop_msg (p,POP_FAILURE,
  578.             "Unable to copy mail spool file, quota exceeded (%d)",
  579.             errno);
  580. #endif
  581.         return pop_msg (p,POP_FAILURE,
  582.         "Unable to copy mail spool file to temp pop dropbox %s (%d)",
  583.             p->temp_drop, errno);
  584.     }
  585.  
  586.     if ((content_nchar >= content_length) &&
  587.         (p->mmdf_separator ? !strcmp(p->mmdf_separator, buffer) :
  588.         isfromline(buffer))) {
  589.  
  590.         if (expecting_trailer) {
  591.         expecting_trailer = 0;
  592.         continue;
  593.         }
  594.  
  595.         MD5Init (&mdContext);
  596.         MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  597.  
  598.         if (!inheader) {
  599.         if (++msg_num > p->msg_count) {
  600.             p->mlp=(MsgInfoList *) realloc(p->mlp,
  601.             (p->msg_count+=ALLOC_MSGS)*sizeof(MsgInfoList));
  602.             if (p->mlp == NULL) {
  603.             (void)close (mfd);
  604.             (void)close (dfd);
  605.             p->msg_count = 0;
  606.             return pop_msg (p,POP_FAILURE,
  607.                 "Can't build message list for '%s': Out of memory",
  608.                 p->user);
  609.             }
  610.             mp = p->mlp + msg_num - 2;
  611.         }
  612. #ifdef DEBUG
  613.         if(p->debug && msg_num != 1)
  614.             pop_log(p,POP_DEBUG,
  615.         "Msg %d uidl %s at offset %d is %d octets long and has %u lines.",
  616.         mp->number,mp->uidl_str,mp->offset,mp->length,mp->lines);
  617. #endif
  618.         ++mp;
  619.  
  620.         } else {
  621.         pop_log(p,POP_DEBUG,
  622.             "Msg %d corrupted, ignoring previous header information.",
  623.              mp->number);
  624.         }
  625.  
  626.             mp->number = msg_num;
  627.             mp->length = 0;
  628.             mp->lines = 0;
  629.             mp->body_lines = 0;
  630.             mp->offset = ftell(p->drop) - nchar;
  631.             mp->del_flag = FALSE;
  632.             mp->retr_flag = FALSE;
  633.             mp->orig_retr_state = FALSE;
  634.         mp->uidl_str = "\n";
  635.  
  636. #ifdef DEBUG
  637.             if(p->debug)
  638.                 pop_log(p,POP_DEBUG, "Msg %d being added to list", mp->number);
  639. #endif
  640.         inheader = 1;
  641.         content_length = 0;
  642.         content_nchar = 0;
  643.         cont_len = 0;
  644.         uidl_found = 0;
  645.         if (p->mmdf_separator)
  646.         expecting_trailer = 1;
  647.  
  648.         continue;    /* Do not include From separator in message size */
  649.         } 
  650.  
  651.     if (inheader) {
  652.         if (*buffer == '\n') {
  653.         inheader = 0;
  654.         mp->body_lines = 1;
  655.         content_length = cont_len;
  656.  
  657.         if (!uidl_found) {
  658.             char *cp;
  659.             int  i;
  660.  
  661.             MD5Final (digest, &mdContext);
  662.             cp = mp->uidl_str = (char *)malloc((DIG_SIZE * 2) + 2);
  663.  
  664.             for (i = 0; i < DIG_SIZE; i++, cp+=2) {
  665.             sprintf(cp, "%02x", digest[i]);
  666.             }
  667.             *cp++ = '\n';
  668.             *cp   = '\0';
  669.  
  670.             mp->length += strlen("X-UIDL: ") + strlen(mp->uidl_str) + 1;
  671.             p->drop_size += strlen("X-UIDL: ") + strlen(mp->uidl_str)+1;
  672.  
  673.     /* New UIDs do not dirty the mailspool if NO_STATUS is set.  They
  674.        are just recalculated each time the popper is run or LMOS is
  675.        set and the mail spool is updated.
  676.      */
  677. #ifndef NO_STATUS
  678.             p->dirty = 1;
  679. #endif
  680.         }
  681.  
  682.         } else if (CONTENT_LENGTH && !strncmp(buffer, "Content-Length:", 15)) {
  683.         cont_len = atoi(buffer + 15);
  684.         MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  685.         continue;  /* Not included in message size */
  686.  
  687.         } else if (!uidl_found && (!strncasecmp("Received:", buffer, 9) ||
  688.                        !strncasecmp("Date:", buffer, 5) ||
  689.                        !strncasecmp("Message-Id:",buffer, 11) ||
  690.                        !strncasecmp("Subject:",buffer, 8)
  691.                        )) {
  692.         MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  693.         } else if (!strncasecmp("X-UIDL:", buffer, 7)) {
  694.         if (!uidl_found) {
  695.             char *cp;
  696.  
  697.             uidl_found++;
  698.  
  699.             /* Skip over header */
  700.             cp = buffer;
  701.             if (cp = index(buffer, ':')) {
  702.             cp++;
  703.             while (*cp && (*cp == ' ' || *cp == '\t')) cp++;
  704.             } else
  705.             cp = "";
  706.  
  707.             mp->uidl_str = (char *)strdup(cp);
  708.             mp->length += nchar + 1;
  709.             p->drop_size += nchar + 1;
  710.         }
  711.         continue;  /* Do not include this value in the message size */
  712.         } else if (!strncasecmp(buffer,"Status:",7)) {
  713.         if (index(buffer, 'R') != NULL) {
  714.             mp->retr_flag = TRUE;
  715.             mp->orig_retr_state = TRUE;
  716.         }
  717.         }
  718.     } else {
  719.         content_nchar += nchar;
  720.         mp->body_lines++;
  721.     }
  722.  
  723.         mp->length += nchar + 1;
  724.         p->drop_size += nchar + 1;
  725.         mp->lines++;
  726.     }
  727.  
  728.     p->msg_count = msg_num;
  729.  
  730. #ifdef DEBUG
  731.     if(p->debug && msg_num > 0) {
  732.         register    i;
  733.         for (i = 0, mp = p->mlp; i < p->msg_count; i++, mp++)
  734.             pop_log(p,POP_DEBUG,
  735.         "Msg %d uidl %s at offset %d is %d octets long and has %u lines.",
  736.         mp->number,mp->uidl_str,mp->offset,mp->length,mp->lines);
  737.     }
  738. #endif
  739.  
  740.     if (fflush(p->drop) == EOF)
  741.         return pop_msg(p,POP_FAILURE,"Flush of temp pop dropbox %s failed (%d)",
  742.         p->temp_drop, errno);
  743.  
  744.     return(POP_SUCCESS);
  745. }
  746.  
  747. /* 
  748.  *  dropcopy:   Make a temporary copy of the user's mail drop and 
  749.  *  save a stream pointer for it.
  750.  */
  751.  
  752. pop_dropcopy(p, pwp)
  753. POP     *   p;
  754. struct passwd    *    pwp;
  755. {
  756.     int                     mfd;                    /*  File descriptor for 
  757.                                                         the user's maildrop */
  758.     int                     dfd;                    /*  File descriptor for 
  759.                                                         the SERVER maildrop */
  760.     FILE            *tf;            /*  The temp file */
  761.     int                tfn;            
  762.     char                    buffer[MAXLINELEN];     /*  Read buffer */
  763.     long                    offset;                 /*  Old/New boundary */
  764.     int                     nchar;                  /*  Bytes written/read */
  765.     struct stat             mybuf;                  /*  For fstat() */
  766.  
  767.     if (genpath(p) < 0)
  768.     return(pop_msg(p, POP_FAILURE, "Unable to create temporary drop name"));
  769.  
  770.     /*  Create a temporary maildrop into which to copy the updated maildrop */
  771.     (void)sprintf(p->temp_drop, POP_DROP, p->user);
  772.  
  773. #ifdef DEBUG
  774.     if(p->debug)
  775.         pop_log(p,POP_DEBUG,"Creating temporary maildrop '%s'",
  776.             p->temp_drop);
  777. #endif
  778.  
  779. #ifdef BULLDB
  780.     if (p->bulldir) {
  781.     char bull_db[MAXLINELEN];
  782.  
  783. #ifdef BULLDBDIR
  784.     sprintf(bull_db, "%s/bulldb", BULLDBDIR);
  785. #else
  786.     sprintf(bull_db, "%s/bulldb", p->bulldir);
  787. #endif
  788.         if ((p->bull_db = dbm_open (bull_db, O_RDWR | O_CREAT, 0600)) == NULL) {
  789.         return(pop_msg(p, POP_FAILURE,
  790.            "Unable to open Bulletin database, contact your administrator"));
  791.     }
  792.     }
  793. #endif
  794.  
  795.     /* Here we work to make sure the user doesn't cause us to remove or
  796.      * write over existing files by limiting how much work we do while
  797.      * running as root.
  798.      */
  799.  
  800. #ifdef BINMAIL_IS_SETGID
  801. # if BINMAIL_IS_SETGID > 1
  802.     pwp->pw_gid = (gid_t)BINMAIL_IS_SETGID;
  803. # else
  804.     if (!stat(POP_MAILDIR, &mybuf))
  805.     pwp->pw_gid = mybuf.st_gid;
  806. # endif
  807. #endif
  808.  
  809.     /* Now we run as the user. */
  810.     (void) setgid((GID_T)pwp->pw_gid);
  811.     (void) setuid((UID_T)pwp->pw_uid);
  812.  
  813. #ifdef DEBUG
  814.     if(p->debug)pop_log(p,POP_DEBUG,"uid = %d, gid = %d",getuid(),getgid());
  815. #endif
  816.  
  817.     if ((dfd = open(p->temp_drop, O_RDWR | O_CREAT, 0600)) == -1) {
  818.         pop_log(p, POP_PRIORITY,
  819.             "Unable to open temporary maildrop '%s': %s (%d)",p->temp_drop,
  820.                 (errno < sys_nerr) ? sys_errlist[errno] : "", errno) ;
  821.         return pop_msg(p,POP_FAILURE,
  822.         "System error, can't open temporary file, do you own it?");
  823.     }
  824.  
  825.     fstat(dfd, &mybuf);
  826.     if (mybuf.st_uid != pwp->pw_uid) {
  827.     close(dfd);
  828.     return(pop_msg(p, POP_FAILURE, "Temporary drop file not owned by %s.",
  829.         p->user));
  830.     }
  831. #ifdef NEXT
  832.     if (mybuf.st_mode & (0x7)) {
  833. #else
  834.     if (mybuf.st_mode & (S_IWOTH | S_IROTH)) {
  835. #endif
  836.     close(dfd);
  837.     return(pop_msg(p, POP_FAILURE,
  838.       "Your temporary file %s is accessable by others.  This must be fixed",
  839.         p->temp_drop));
  840.     }
  841.     /* Make sure the mailspool is not a hard link */
  842.     if (mybuf.st_nlink != 1) {
  843.     close(dfd);
  844.     return(pop_msg(p, POP_FAILURE,
  845.         "Your temporary file appears to have more than one link."));
  846.     }
  847.  
  848.     /* If the temporary popdrop is not empty, revert to regular mode. */
  849.     if (mybuf.st_size != 0)
  850.     p->server_mode = 0;
  851.  
  852. #if defined(S_ISREG)
  853.     /* Make sure the file is not a symbolic link reference */
  854.     lstat(p->temp_drop, &mybuf);
  855.     if (!S_ISREG(mybuf.st_mode)) {
  856.     close(dfd);
  857.     return pop_msg(p, POP_FAILURE,
  858.     "Your temporary drop file %s is not type 'regular file'", p->temp_drop);
  859.     }
  860. #endif
  861.  
  862.     /*  Lock the temporary maildrop */
  863.     if ( flock (dfd, LOCK_EX|LOCK_NB) == -1 ) {
  864.     switch(errno) {
  865.         case EWOULDBLOCK:
  866.         return pop_msg(p,POP_FAILURE,
  867.              "%s lock busy!  Is another session active? (%d)",
  868.                             p->temp_drop, errno);
  869.         /* NOTREACHED */
  870.         default:
  871.         return pop_msg(p,POP_FAILURE,"flock: '%s': %s (%d)",
  872.         p->temp_drop, (errno < sys_nerr) ? sys_errlist[errno] : "", errno);
  873.         /* NOTREACHED */
  874.     }
  875.     }
  876.     
  877. #ifndef KEEP_TEMP_DROP
  878.     /* check for race conditions involving unlink.  See pop_updt.c */
  879.     /* s-dorner@uiuc.edu, 12/91 */
  880.     {
  881.       struct stat byName, byFd;
  882.       if (stat(p->temp_drop, &byName) || fstat(dfd, &byFd) ||
  883.       byName.st_ino != byFd.st_ino)
  884.       {
  885.         return pop_msg(p,POP_FAILURE,
  886.         "Maildrop being unlocked; try again.");
  887.       }
  888.     }
  889. #endif
  890.     
  891.     /* If in server mode and the temporary popdrop has any data in it
  892.        then revert back to the original way of dealing with pop drops.
  893.      */
  894.  
  895.     /*  Acquire a stream pointer for the temporary maildrop */
  896.     if ( (p->drop = fdopen(dfd,"r+")) == NULL ) {
  897.         (void)close(dfd) ;
  898.         return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s (%d)",
  899.             p->temp_drop, errno);
  900.     }
  901.  
  902.     if (!p->server_mode) {
  903.     /* In server mode this file is used as a process lock and a temporary
  904.        copy file later on */
  905.  
  906.     if (init_dropinfo(p) != POP_SUCCESS)
  907.         return(POP_FAILURE);
  908.  
  909.     /* Sync with stdio */
  910.     (void)fseek(p->drop, 0L, SEEK_END);
  911.     offset = ftell(p->drop);
  912.     /* Get the location of the next file */
  913. /*    offset = lseek(fileno(p->drop), (OFF_T)0, L_XTND); */
  914.     }
  915.  
  916. #ifdef MAILOCK
  917.     /*  Lock the maildrop */
  918.     if (maillock(p->user,1) != 0)
  919.             return pop_msg(p,POP_FAILURE, "maillock: '%s'", p->temp_drop);
  920. #endif
  921.  
  922.     /*  Open the user's maildrop, If this fails,  no harm in assuming empty */
  923.     if ((mfd = open(p->drop_name, O_RDWR)) > 0) {
  924.         /* Lock the maildrop */
  925.         if (flock (mfd,LOCK_EX) == -1)
  926.     {
  927.             (void)close(mfd) ;
  928. #ifdef MAILOCK
  929.         mailunlock();
  930. #endif
  931.             return pop_msg(p,POP_FAILURE, "flock: '%s': %s (%d)", p->temp_drop,
  932.                 (errno < sys_nerr) ? sys_errlist[errno] : "", errno);
  933.         }
  934.  
  935.     if (!p->server_mode) {
  936.         /* New routine to copy and get dropbox info all at the same time */
  937.         nchar = do_drop_copy(p, mfd, dfd);
  938.  
  939.         if ( nchar != POP_SUCCESS ) {
  940.         /* pop_dropcopy has integrated the info gathering pass into
  941.            the copy pass so now the information of the dropfile is
  942.            inconsistant if there is an error.  Now we exit instead
  943.            of trying to continue with what is available.
  944.         */
  945.         (void)ftruncate(dfd, (OFF_T)offset) ;
  946.         return(nchar);
  947.         } else {
  948.         /* Mail transferred!  Zero the mail drop NOW,  that we
  949.            do not have to do gymnastics to figure out what's new
  950.            and what is old later */
  951.         (void)ftruncate(mfd, (OFF_T)0) ;
  952.         }
  953.  
  954.         /*  Close the actual mail drop */
  955.         (void)close (mfd);
  956.     } else {
  957.         /* Save the temporary drop FILE and fid values */
  958.         p->hold = p->drop;
  959.         if ((p->drop = fdopen(mfd,"r+")) == NULL) {
  960.         (void)close(dfd) ;
  961.         return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s (%d)",
  962.             p->drop_name, errno);
  963.         }
  964.  
  965.         if (init_dropinfo(p) != POP_SUCCESS)
  966.         return(POP_FAILURE);
  967.  
  968.         dfd = mfd;
  969.     }
  970.     } 
  971.  
  972.     /* Recalculate offset */
  973.     (void)fseek(p->drop, 0L, SEEK_END);
  974.     offset = ftell(p->drop);
  975.  
  976.     if ((p->bulldir != NULL) && (pop_bull(p, pwp) != POP_SUCCESS)) {
  977.     /* Return pop drop back to what it was before the bulletins */
  978.     (void)ftruncate(dfd, (OFF_T)offset);
  979.     }
  980.  
  981.     (void)fseek(p->drop, 0L, SEEK_END);
  982.     p->spool_end = ftell(p->drop);
  983.  
  984. #ifdef MAILOCK
  985.     mailunlock();
  986. #endif
  987.  
  988.     if (p->server_mode)
  989.         flock(mfd, LOCK_UN);
  990.  
  991.     return(POP_SUCCESS);
  992. }
  993.  
  994.